package roboticsfmw.core;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;


public class EventBus {

	private Map<Class<? extends Event>,Set<ProcessorMethodEntry>> eventMap;
	
	public EventBus() {
		eventMap = new HashMap<Class<? extends Event>,Set<ProcessorMethodEntry>>();
	}
	
	public synchronized void registerEvent(Class<? extends Event> c, Processor processor, Method method) {
		Set<ProcessorMethodEntry> processMethodSet = eventMap.get(c); 
		if (processMethodSet==null){
			processMethodSet = new TreeSet<ProcessorMethodEntry>();
			eventMap.put(c, processMethodSet);
		}
		ProcessorMethodEntry pme = new ProcessorMethodEntry(processor, method);
		processMethodSet.add(pme);
	}
	
	public synchronized void notify(Event event) {
		Set<ProcessorMethodEntry> processMethodSet = eventMap.get(event.getClass());
		if (processMethodSet!=null) {
			for (ProcessorMethodEntry processorMethodEntry : processMethodSet) {
				Method method = processorMethodEntry.getMethod();
				Processor processor = processorMethodEntry.getProcessor();
				try {
					method.invoke(processor,event);
				} catch (Exception e) {
				}
			}
		}
	}
	
	
	public class ProcessorMethodEntry implements Comparable<ProcessorMethodEntry>{
		
		private Processor processor;
		private Method method;
				
		public ProcessorMethodEntry(Processor processor, Method method) {
			this.processor = processor;
			this.method = method;
		}

		public Processor getProcessor() {
			return processor;
		}

		public void setProcessor(Processor processor) {
			this.processor = processor;
		}

		public Method getMethod() {
			return method;
		}

		public void setMethod(Method method) {
			this.method = method;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result	+ ((method == null) ? 0 : method.hashCode());
			result = prime * result	+ ((processor == null) ? 0 : processor.hashCode());
			return result;
		}


		@Override
		public boolean equals(Object obj) {
			
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			
			ProcessorMethodEntry other = (ProcessorMethodEntry) obj;
			
			if (this.method == null) {
				if (other.method != null)
					return false;
			} else if (!this.method.equals(other.method))
				return false;
			
			if (this.processor == null) {
				if (other.processor != null)
					return false;
			} else if (!this.processor.equals(other.processor))
				return false;
			
			return true;
		}

		@Override
		public int compareTo(ProcessorMethodEntry o) {
			if (this.equals(o)) {
				return 0;
			} else {
				return 1;
			}
		}
	}
	
	
}
